const {v4: uuidv4} = require('uuid');
const createModel = require('../mongodb/createModel')
const {getMaxTopByUserId} = require("../utils/article");
const {setArticleViewCount} = require("../utils/article");
const {setUserViewArticles, includeMenuByMenuId, includeUserById} = require("../utils/article");

// 文章模型
const schema = {
    // 用户id
    userId: {type: String, required: true},
    // ID
    articleId: {type: String, required: true},

    /* 新增上传 */
    // 菜单ID
    menuId: {type: String, default: ''},
    // 标题
    title: {type: String, required: true, trim: true},
    // html内容
    content: {type: String, required: true},
    // markdown内容
    markdownContent: {type: String, required: true},
    // 标签
    tags: {type: String, default: '', trim: true},
    // 封面
    cover: {type: String, default: ''},

    /* 修改状态上传 */
    // 状态(0回收站,1发布,2草稿)
    status: {type: Number, default: 1, required: true},
    // 发布时间
    postTime: {type: Date, default: null},

    /* 数目默认全部为0 */
    // 评论数
    commentCount: {type: Number, default: 0},
    // 阅读数
    viewCount: {type: Number, default: 0},

    /* 置顶操作 */
    // 置顶 0未置顶 1-n 置顶顺序
    top: {type: Number, default: -1},

    // 创建时间
    createTime: {type: Date, default: Date.now}
}

const model = createModel('articles', schema);

/**
 * 发布文章
 * @param params    传参 userId menuId title content markdownContent tags status
 * @returns {Promise<object>} 结果
 */
const handleAdd = (params) => {
    return new Promise(async (resolve, reject) => {
        delete params.createTime;
        delete params.commentCount;
        delete params.viewCount;
        delete params.top;
        params.status = Number(params.status);
        if (params.status !== 1 && params.status !== 2) {
            return reject({code: 0, data: null, msg: '文章状态异常'})
        }
        const isUser = await includeUserById({userId: params.userId});
        if (!isUser) {
            return reject({code: 0, data: null, msg: '用户不存在'})
        }
        params.articleId = uuidv4();
        params.postTime = params.status === 1 ? Date.now() : null;
        params.menuId = await includeMenuByMenuId({userId: params.userId, menuId: params.menuId});
        model.create(params, (err, docs) => {
            if (!err) {
                resolve({code: 1, data: null, msg: '发布成功'});
            } else {
                reject({code: 0, data: null, msg: err.message});
            }
        })
    })
}

/**
 * 文章删除
 * @param params  传参 userId articleId
 * @returns {Promise<object>} 结果
 */
const handleDel = (params) => {
    return new Promise((resolve, reject) => {
        model.deleteOne({userId: params.userId, articleId: params.articleId}, (err, docs) => {
            if (!err) {
                resolve({code: 1, data: null, msg: '删除成功'});
            } else {
                reject({code: 0, data: null, msg: err.message});
            }
        })
    })
}

/**
 * 查询具体文章
 * @param params    传参  articleId
 * @returns {Promise<object>} 结果
 */
const handleInfo = (params) => {
    return new Promise((resolve, reject) => {
        const aggregate = [
            {
                $match: {articleId: params.articleId}
            },
            {
                $lookup: {
                    from: 'users',
                    localField: 'userId',
                    foreignField: 'id',
                    as: 'userInfo',
                }
            },
            {
                $unwind: {
                    path: '$userInfo',
                    preserveNullAndEmptyArrays: true
                },
            },
            {
                $lookup: {
                    from: 'menus',
                    localField: 'menuId',
                    foreignField: 'menuId',
                    as: 'menuInfo',
                },
            },
            {
                $unwind: {
                    path: '$menuInfo',
                    preserveNullAndEmptyArrays: true
                },
            },
            {
                $project: {
                    _id: 0, __v: 0,
                    'userInfo._id': 0, 'userInfo.__v': 0, 'userInfo.password': 0,
                    'menuInfo._id': 0, 'menuInfo.__v': 0
                }
            }
        ]
        model.aggregate(aggregate, async (err, docs) => {
            if (!err) {
                await setArticleViewCount(model, params).catch(error => reject(error));
                await setUserViewArticles(params).catch(error => reject(error));
                resolve({code: 1, data: docs[0], msg: '查询成功'});
            } else {
                reject({code: 0, msg: err.message});
            }
        })
    })
}

/**
 * 修改
 * @param params    传参 userId articleId -- menuId title content markdownContent tags status top
 * @returns {Promise<object>} 结果
 */
const handleModify = (params) => {
    return new Promise(async (resolve, reject) => {
        const filter = {
            userId: JSON.parse(JSON.stringify(params)).userId,
            articleId: JSON.parse(JSON.stringify(params)).articleId
        }
        delete params.userId;
        delete params.articleId;
        delete params.commentCount;
        delete params.viewCount;
        delete params.createTime;
        params.postTime = params.status === 1 ? Date.now() : null;
        model.findOneAndUpdate(filter, params, (err, docs) => {
            if (!err) {
                resolve({code: 1, data: null, msg: '修改成功'});
            } else {
                reject({code: 0, data: null, msg: err.message});
            }
        })
    })
}


/**
 * 查询文章
 * 示例：
 * {
 *     page: 1,
 *     size: 10,
 *     userId: '',
 *     menuId: '',
 *     title: '',
 *     content: '',
 *     markdownContent: '',
 *     tags: '',
 *     status: 0,
 *     postTimeStart: '',
 *     postTimeEnd: '',
 *     commentCountMin: '',
 *     commentCountMax: '',
 *     viewCountMin: '',
 *     viewCountMax: '',
 *     top: -1, // -1查置顶 -2或者不传查全部 数字越大越靠前
 *     createTimeStart: '',
 *     createTimeEnd: '',
 * }
 * @param params    传参 (页码,数据量,用户ID,菜单ID,标题,html内容,markdown内容,标签,状态,发布时间,评论量,阅读量,点赞量,是置顶,创建时间)
 * @returns {Promise<object>} 结果
 */
const handleList = (params) => {
    const page = Number(params.page);
    const size = Number(params.size);
    const filter = {
        $match: {
            $and: [
                params.userId ? {userId: params.userId} : {},
                params.menuId ? {menuId: params.menuId} : {},
                {title: {$regex: params.title || '', $options: 'i'}},
                {content: {$regex: params.content || '', $options: 'i'}},
                {markdownContent: {$regex: params.markdownContent || '', $options: 'i'}},
                {tags: {$regex: params.tags || '', $options: 'i'}},
                params.status ? {status: Number(params.status)} : {},
                params.postTimeStart ? {postTime: { $gte: new Date(params.postTimeStart + ' 00:00:00')} } : {},
                params.postTimeEnd ? {postTime: { $lte: new Date(params.postTimeEnd + ' 23:59:59')} } : {},
                params.commentCountMin ? {commentCount: { $gte: Number(params.commentCountMin)} } : {},
                params.commentCountMax ? {commentCount: { $lte: Number(params.commentCountMax)} } : {},
                params.viewCountMin ? {viewCount: { $gte: Number(params.viewCountMin)} } : {},
                params.viewCountMax ? {viewCount: { $lte: Number(params.viewCountMax)} } : {},
                params.top ? {top: {$ne: Number(params.top)}} : {},
                params.createTimeStart ? {createTime: { $gte: new Date(params.createTimeStart + ' 00:00:00')} } : {},
                params.createTimeEnd ? {createTime: { $lte: new Date(params.createTimeEnd + ' 23:59:59')} } : {},
            ]
        }
    };
    const aggregate = [{
        $facet: {
            total: [filter, {$count: 'total'}],
            list: [
                filter,
                {
                    $lookup: {
                        from: 'users',
                        localField: 'userId',
                        foreignField: 'id',
                        as: 'userInfo'
                    }
                },
                {
                    $unwind: {
                        path: '$userInfo',
                        preserveNullAndEmptyArrays: true
                    },
                },
                {
                    $lookup: {
                        from: 'menus',
                        localField: 'menuId',
                        foreignField: 'menuId',
                        as: 'menuInfo'
                    },
                },
                {
                    $unwind: {
                        path: '$menuInfo',
                        preserveNullAndEmptyArrays: true
                    },
                },
                {$sort: {top: -1, createTime: -1}},
                {$skip: (page - 1) * size},
                {$limit: size},
                {
                    $project: {
                        _id: 0, __v: 0,
                        'userInfo._id': 0, 'userInfo.__v': 0, 'userInfo.password': 0,
                        'userInfo.commentArticles': 0, 'userInfo.viewArticles': 0,
                        'menuInfo._id': 0, 'menuInfo.__v': 0
                    }
                }
            ],
        }
    }]
    return new Promise((resolve, reject) => {
        model.aggregate(aggregate, (err, docs) => {
            if (!err) {
                resolve({
                    code: 1,
                    data: {
                        page, size,
                        total: docs[0].total[0] ? docs[0].total[0].total : 0,
                        list: docs[0].list
                    },
                    msg: '查询成功'
                });
            } else {
                reject({code: 0, data: null, msg: err.message});
            }
        })
    })
}

/**
 * 置顶
 * @param params isTop 1置顶 0取消置顶
 * @returns {Promise<object>} 结果
 */
const handleTop = (params) => {
    return new Promise(async (resolve, reject) => {
        const filter = {
            userId: params.userId,
            articleId: params.articleId,
        }
        params.isTop = !!Number(params.isTop);
        let maxTop;
        if (params.isTop) {
            maxTop = await getMaxTopByUserId(model, params).catch(error => reject(error));
            if (maxTop && maxTop.code === 1) {
                if (maxTop.data.articleId === params.articleId) {
                    return reject({code: 0, data: null, msg: '已是最顶部文章，无法再次进行置顶'})
                }
            }
        }
        model.findOneAndUpdate(filter, {top: params.isTop ? (maxTop.top + 1) : -1}, (err, docs) => {
            if (!err) {
                resolve({code: 1, data: null, msg: '置顶修改成功'});
            } else {
                reject({code: 0, data: null, msg: err.message});
            }
        })
    })
}

module.exports = {model, handleAdd, handleList, handleModify, handleDel, handleInfo, handleTop}
